 <?php
namespace Admin\Model;
use Think\Model;

class CategoryModel extends Model{
	
	protected $insertFields='cat_name,parent_id';
	protected $_validate=array(
			array('cat_name','require','分类名称不能为空',1),
	); 
	
	public function getTree(){
		$data = $this->select();
		return $this->_getTree($data);
	}
	
	/**
	 * 
	 * 函数功能：把一个数组变成父子级排序
	 * @param array $data 要排序的数据
	 * @param number $parent_id父ID，每次传入时值不同
	 * @param number $level 当前是第几层级，默认是0（最顶层父级）
	 */
	private function _getTree($data,$parent_id=0,$level=0){
		/*
		 * 这个静态变量用于存放重新排序好的数组
		 * 因为递归是自己调用自己，所以为了防止每次调用时数组被初始化
		 * 所以要用静态变量在这个方法中保存这个数组中的值，直到全部排序完毕
		 */
		static  $_ret = array();
		foreach($data as $v){//开始对传入的原数组进行循环遍历
			/* 看本函数的第二个参数：如果数组中的parent_id字段和传进来的父ID相等
			 * 说明当前循环到的这个数组元素，是某个元素的子元素
			 * 注意：0除外，若parent_id字段是0，说明他自己就是父元素
			 */
			if($v['parent_id'] == $parent_id){
				$v['level'] = $level;//把当前的层级存入到数组元素的level字段中
				$_ret[] = $v;//把当前数组元素添加到静态数组$_ret中
				//此时添加到$_ret数组中的元素，就是排好序的，因为：请看当前的if条件
				
				/*
				 * 此时调用自己，也相当于再次嵌套foreach 进行循环
				 * 因为本次foreach循环时，父元素是0，就是说只能找到一级
				 * 而再次调用自己，传入的$parent_id是子元素的ID，也就是说
				 * 要继续遍历子元素，看看其下有没有子级
				 * 以此类推，每次都再次调用自己，相当于让每个子级都去循环，看看是否它还有子级
				 * 所以这个递归不用出口，因为子级肯定是有限的，直到最后，
				 * $v['parent_id'] == $parent_id这个他条件不再成立时，
				 * 也就不会进入这个If，所以也就不会再调用自己了。
				 * 最终，每个排好序的数组元素都会被存入静态数组$_ret中，相应的等级也会存进去
				 * 等级的作用是方便我们在前台输出时，能够输出缩进关系的一个字段
				 */
				$this->_gettree($data,$v['id'],$level+1);
			}
		}
		return $_ret;
	}
	
	public function getChildren($catId){
		$data = $this->select();
		return $this->_getChildren($data, $catId,true);
	}
	
	/*
	 * 获取一个分类下面所有的子分类ID
	 */
	private function _getChildren($data,$parent_id,$isClear=false){
		static $_ret = array();
		if($isClear){
			$_ret = array();
		}
		foreach ($data as $k => $v)
		{
			if($v['parent_id'] == $parent_id)
			{
				$_ret[] = $v['id'];
				$this->_getChildren($data, $v['id']);
			}
		}
		return $_ret;
	}
	
	protected function _before_delete($options){
		$children=$this->getChildren($options['where']['id']);
		if($children){
			//delete方法的返回值是删除的记录数，如果返回值是false则表示SQL出错，返回值如果为0表示没有删除任何数据
			//说明，可以考虑判断$res，如果失败就直接终止程序等等。
			$where['id']=array('in',$children);
			$res = M('Category')->where($where)->delete();	
			
			/*
			 * 说明：正常情况的需求一般都是：如果一个分类下面有子分类，
			 * 则不允许该分类进行删除，必须先删除子分类，有安全性
			 * 具体情况根据客户需求限定
			 * 但是这种删除子分类的方式我们要会
			 */
		}
	}
	
}











